#include "call_list.h"

/* Standard call list - selecting next transmitter in the initial ordering; */

/** Inicializace prvotniho setrideni. Nastavi aktualni pozici na zacatek.
 * \param ordering pocatecni setrideni vysilacu
 */
void CallList::initialize(int * ordering) {
	this->ordering = ordering;
	position = -1;
	span = 0;
}

/** Priradi aktualnimu vysilaci danou frekvenci.
 * \param f frekvence prirazena aktualnimu vysilaci
 */
void CallList::assign(int f) {
	if (f > span) span = f;
}

/** Presune se na dalsi vysilac. Aktualnim vysilacem se stane ten nasledujici
 * podle prvotniho setrideni, tedy zadne preusporadavani nenastava.
 * \return true, pokud dalsi vysilac existuje 
 */
bool CallList::getNext() {
	if (++position == area->size) {
		position = -1;
		return false;
	}
	else {
		return true;
	}
}

// Generalized Saturatio Degree call list

/** Inicializace preusporadavajiciho seznamu prvotnim setridenim. Toto setrideni bude 
 * v prubehu algoritmu meneno podle aktualni situace.
 * \param ordering pocatecni setrideni vysilacu
 */
void GSDCallList::initialize(int * ordering) {
	CallList::initialize(ordering);
	int i;
	for (i = 0; i < area->size; ++i) {
		call_degree[i] = 0;
		init_position[ordering[i]] = i;
	}
	for (i = 0; i < area->size * frequencies; ++i) {
		degrees[i] = 0;
	}
}

/** Priradi aktualnimu vysilaci danou frekvenci a provede vypocet jejiho vlivu na okolni vysilace.
 * \param f frekvence prirazena aktulanimu vysilaci
 */
void GSDCallList::assign(int f) {
	int d, cell;
	if (span < f) span = f;
	cell = area->findCell(ordering[position]);
	for (int i = 0; i < area->size; ++i) {
		d = area->frequencyDistance(cell, area->findCell(i));
		if (degrees[(f - 1) * area->size + i] < d) {
			call_degree[i] += d - degrees[(f - 1) * area->size + i];
			degrees[(f - 1) * area->size + i] = d;
		}
	}
}

/** Vrati dalsi vysilac. Dalsim vysilacem je ten, ktery ma nejvetsi stupen (tedy nejmene povolenych frekvenci).
 * \return true, pokud dalsi vysilac existuje 
 */
bool GSDCallList::getNext() {
	if (++position == area->size) {
		position = -1;
		return false;
	}
	int max = ordering[position], max_pos = position;
	for (int i = position; i < area->size; ++i) {
		if (call_degree[ordering[i]] > max || (call_degree[ordering[i]] == max && init_position[ordering[i]] < init_position[ordering[max_pos]])) {
			max_pos = i;
			max = call_degree[ordering[i]];
		}
	}
	/* swap max_pos and position in ordering */
	if (position != max_pos) {
		max = ordering[position];
		ordering[position] = ordering[max_pos];
		ordering[max_pos] = max;
	}
	return true;
}
